<script setup lang="ts">
import type { ClinicDefaultAppointmentTimeDO, ClinicTimeCountRespVO } from '@/api/clinic-schedule';
import type { DAY_PERIOD_TYPE } from '@/enums/date.enums';
import dayjs from 'dayjs';
import { computed, ref } from 'vue';
import { ClinicScheduleApi } from '@/api/clinic-schedule';
import AuthBar from '@/components/authBar/index.vue';
import Empty from '@/components/empty/index.vue';
import { dayPeriodTypeList } from '@/enums/date.enums';
import { APPOINTMENT_SEARCH_TYPE } from '@/enums/registration.enums';
import { useRequest } from '@/hooks/useRequest';
import { buildAssetSource } from '@/utils';
import { dictVal2Text } from '@/utils/dict.utils';
import { isEmpty } from '@/utils/is.utils';
import { currRoute, withQueryString } from '@/utils/router.utils';
import AppointmentPopup from './components/appointmentPopup.vue';
import Calendar from './components/calendar.vue';
import DoctorCard from './components/doctorCard.vue';
import Steps from './components/steps.vue';
import { useRegistrationTime } from './hooks/useRegistrationTime';

const { query } = currRoute();

// 来源为非时间搜索类型时 显示预约区间日历
const isTimeSearchType = Number(query.type) !== APPOINTMENT_SEARCH_TYPE.TIME;

const { dateType, selectDate, getTimeSlotType, isTimeSlotAvailable } = useRegistrationTime();

function handleDateChange() {
  selectedTime.value = undefined;
  getDoctor();
}

const {
  data: doctor,
  runAsync: getDoctor
} = useRequest(() => ClinicScheduleApi.getDoctorList({
  doctorId: query.doctorId as unknown as number,
  appointmentDate: selectDate.value.format('YYYY-MM-DD')
}).then(res => {
  res[0]?.visitTime.sort((a, b) => {
    return dayjs(a.startTime, 'HH:mm').diff(dayjs(b.startTime, 'HH:mm'));
  });
  return res[0];
}), {
  manual: isTimeSearchType,
  onSuccess(data) {
    // 优先判断当前选择的时间区间是否可预约
    const result = data.visitTime.find(item => getTimeSlotType(item) === dateType.value && isTimeSlotAvailable(item));
    if (!result) {
      // 自动切换到可选择的时间段
      const availableTime = data.visitTime.find(item => isTimeSlotAvailable(item));
      if (availableTime) {
        dateType.value = getTimeSlotType(availableTime);
      }
    }
  },
  onBeforeRequest() {
    uni.showLoading({
      title: '加载中',
      mask: true
    });
  },
  onComplete() {
    uni.hideLoading();
  }
});

// 预约区间列表
// 根据 dateType 动态过滤医生出诊时间段
const appointTimeList = computed(() => {
  if (isEmpty(doctor.value))
    return [];
  const { visitTime = [] } = doctor.value;
  return visitTime.filter(item => {
    return getTimeSlotType(item) === dateType.value;
  });
});

const formatAppointTimeList = computed(() => {
  return appointTimeList.value.map(item => {
    if (!isTimeSlotAvailable(item)) {
      return {
        ...item,
        canReserve: false,
        descState: 'disabled',
        countDesc: '-'
      };
    }
    const canReserve = item.count > 0;
    let descState = '';
    if (canReserve) {
      if (item.count <= 2) {
        descState = 'danger';
      }
      else if (item.count <= 3) {
        descState = 'warning';
      }
    }
    else {
      descState = 'disabled';
    }
    return {
      ...item,
      canReserve,
      descState,
      countDesc: canReserve ? `剩余${item.count}号` : '已约满'
    };
  });
});

function handleDateTypeChange(type: DAY_PERIOD_TYPE) {
  dateType.value = type;
  selectedTime.value = undefined;
}

const selectedTime = ref<ClinicTimeCountRespVO>();

function handleAppointTimeClick(item: ClinicTimeCountRespVO) {
  if (!isTimeSlotAvailable(item)) {
    uni.showToast({
      title: '无法预约该时间段',
      icon: 'none'
    });
    return;
  }

  if (item.count <= 0) {
    uni.showToast({
      title: '预约人数已满',
      icon: 'none'
    });
    return;
  }
  selectedTime.value = item;
}

function handleConfirm() {
  if (!selectedTime.value) {
    uni.showToast({
      title: '请选择预约时间',
      icon: 'none'
    });
    return;
  }
  if (!isTimeSlotAvailable(selectedTime.value)) {
    uni.showToast({
      title: '无法预约该时间段',
      icon: 'none'
    });
    selectedTime.value = undefined;
    getDoctor();
    return;
  }
  appointmentPopupRef.value?.onOpen();
}

const appointmentPopupRef = ref<InstanceType<typeof AppointmentPopup>>();
function handleAppointmentTimeConfirm(time: ClinicDefaultAppointmentTimeDO, range: {
  startTime: dayjs.Dayjs
  endTime: dayjs.Dayjs
}) {
  const url = withQueryString('/pages/appointmentRegistration/confirmAppointment', {
    appointmentDateTime: dayjs(`${time.clinicDate} ${time.appointmentTime}`).valueOf(),
    doctorId: doctor.value?.doctorId,
    sectionId: doctor.value?.sectionId,
    appointmentTimeId: time.id,
    timePeriod: `${range.startTime.format('HH:mm')}-${range.endTime.format('HH:mm')}`
  });

  uni.navigateTo({
    url
  });
}
</script>

<template>
  <view class="doctor-appointment flex-col">
    <Steps :current="3" />
    <AuthBar />
    <view class="flex-1 overflow-auto px-48 pt-30">
      <DoctorCard v-if="doctor" :doctor-item="doctor" />

      <Calendar
        v-if="isTimeSearchType" v-model:value="selectDate" class="mt-34" :doctor-id="query.doctorId"
        @change="handleDateChange"
      >
        <template #header>
          <view class="calender-header mb-40 flex items-center justify-between">
            <view>{{ doctor?.sectionName }}门诊排班</view>
            <view>{{ selectDate.format('YYYY-MM-DD') }}</view>
          </view>
        </template>
      </Calendar>

      <view class="appointment-range flex items-center">
        <view
          v-for="item in dayPeriodTypeList.list" :key="item.value" class="appointment-range__item"
          :class="{ active: dateType === item.value }" @click="handleDateTypeChange(item.value)"
        >
          {{ item.label }}
        </view>
      </view>
      <view class="appointment-date flex items-center">
        <view class="mr-41">
          {{ dayjs(selectDate).format('YYYY年MM月DD日') }}
        </view>
        <view class="mr-41">
          {{ dayjs(selectDate).format('dddd') }}
        </view>
        <view>{{ dictVal2Text(dateType, dayPeriodTypeList.list) }}时段</view>
      </view>
      <view class="appointment-time">
        <wd-row :gutter="17">
          <wd-col v-for="item in formatAppointTimeList" :key="item.id" :span="8">
            <view
              class="appointment-time__item mt-20 flex-center flex-col"
              :class="{ disabled: !item.canReserve, active: selectedTime?.id === item.id }"
              @click="handleAppointTimeClick(item)"
            >
              <view class="appointment-item__time">
                {{ item.startTime }}-{{ item.endTime }}
              </view>
              <view class="appointment-item__count" :class="[item.descState]">
                {{ item.countDesc }}
              </view>
            </view>
          </wd-col>
        </wd-row>
        <Empty v-if="isEmpty(formatAppointTimeList)" class="mt-24">
          <template #empty-text>
            暂无出诊时间
          </template>
        </Empty>
      </view>
      <view v-if="!isEmpty(formatAppointTimeList)" class="flex-center">
        <view class="confirm-btn">
          <wd-button block @click="handleConfirm">
            确认
          </wd-button>
        </view>
      </view>

      <view class="footer-tips">
        <view class="footer-tips__title">
          <image :src="buildAssetSource('alert.png')" class="mr-13 h-32 w-32" />温馨提示
        </view>
        <view class="footer-tips__desc">
          <view>请您在预约时间前30分钟到达医院，并在自助机或前台取号。</view>
          <view>若无法按时就诊，请提前取消预约。</view>
        </view>
      </view>
    </view>

    <AppointmentPopup
      ref="appointmentPopupRef" :doctor-id="doctor?.doctorId" :clinic-time="selectedTime"
      :appointment-date="selectDate.format('YYYY-MM-DD')" @confirm="handleAppointmentTimeConfirm"
    />
  </view>
</template>

<route type="page" lang="json5">
{
  layout: 'default',
  style: {
    navigationBarTitleText: '预约挂号',
    navigationStyle: 'custom'
  }
}
</route>

<style lang="scss" scoped>
.doctor-appointment {
  background-color: var(--bg-color);
  height: 100%;

  .calender-header {
    color: var(--secondary-text-color);
    font-size: 34px;
  }

  .appointment-range {
    border-bottom: 1px solid #ffffff;
    margin-top: 65px;

    .appointment-range__item {
      color: #3b3b3b;
      font-size: 36px;
      padding-bottom: 20px;
      margin-right: 41px;

      &.active {
        color: var(--primary);
        font-size: 38px;

        font-weight: bold;
        position: relative;

        &:after {
          position: absolute;
          content: '';
          bottom: 0;
          left: 0;
          width: 100%;
          height: 4px;
          background-color: var(--primary);
        }
      }
    }
  }

  .appointment-date {
    color: #3b3b3b;
    font-size: 38px;

    font-weight: bold;
    margin-top: 63px;
    margin-bottom: 13px;
    padding-left: 18px;
  }

  .appointment-time__item {
    background: #f7fafe;
    border-radius: 10px;
    height: 119px;
    box-sizing: border-box;

    .appointment-item__time {
      font-size: 30px;
      font-weight: 600;
      color: #3d3d3d;
    }

    .appointment-item__count {
      font-size: 24px;
      font-weight: 350;
      color: var(--primary);

      &.danger {
        color: #c83200;
      }

      &.warning {
        color: #cb8100;
      }
    }

    &.active {
      background: var(--primary);

      .appointment-item__time {
        color: #ffffff;
      }

      .appointment-item__count {
        color: #ffffff;
      }
    }

    &.disabled {
      background: rgba(247, 250, 254, 0.5);

      .appointment-item__time {
        color: #8b8e93;
      }

      .appointment-item__count {
        color: #8b8e93;
        text-decoration: line-through;
      }
    }
  }

  .confirm-btn {
    width: 708px;
    --wot-button-medium-height: 124px;
    --wot-button-medium-fs: 42px;
    margin-top: 87px;

    :deep(.wd-button) {
      font-weight: bold;
    }
  }

  .footer-tips {
    background: rgba(247, 250, 254, 0.5);
    box-sizing: border-box;
    height: 208px;
    border-radius: 10px;
    border: 2px solid rgba(255, 255, 255, 0.5);
    padding: 36px 31px;
    margin-top: 87px;
    margin-bottom: 34px;

    .footer-tips__title {
      font-size: 32px;
      font-weight: bold;

      color: #333333;
    }

    .footer-tips__desc {
      font-size: 24px;
      color: var(--secondary-text-color);
    }
  }
}
</style>
